﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.UI.DataVisualization.Charting;
using TestOnlineProject.Models.BusinessLogic;
using TestOnlineProject.Models.Entities;
using PagedList;
using TestOnlineProject.Common;
namespace TestOnlineProject.Controllers
{
    [Authorize]
    public class TestController : Controller
    {
        SubjectBLO subjectBLO = new SubjectBLO();
        SectionBLO sectionBLO = new SectionBLO();
        TestBLO testBLO = new TestBLO();
        SectionQuestionBLO sectionQuestionBLO = new SectionQuestionBLO();
        UserTestBLO userTestBLO = new UserTestBLO();
        UserBLO userBLO = new UserBLO();
        CustomTestBLO customTestBLO = new CustomTestBLO();
        QuestionBLO questionBLO = new QuestionBLO();
        TestTypeBLO testTypeBLO = new TestTypeBLO();
        AnswerBLO answerBLO = new AnswerBLO();
        UserAnswerBLO userAnswerBLO = new UserAnswerBLO();
        ParticipantBLO participantBLO = new ParticipantBLO();

        public ActionResult Index(int? page, string keyWord = "", string createdBy = "", int actualUser = 0, int subjectId = 0, string column = "", string sort = "")
        {
            try
            {
                var subject = subjectBLO.Find(subjectId);

                // Authorize.
                if (subject == null)
                {
                    return HttpNotFound();
                }
                if (!HttpContext.User.IsInRole("1"))
                {
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), subjectId))
                    {
                        var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                        if (user == null)
                        {
                            return RedirectToAction("Error", "Account");
                        }
                        if (!user.IsActivated)
                        {
                            return RedirectToAction("Error", "Account");
                        }

                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Subject");
                    }
                }

                // No. list.
                var noList = new List<NoModel>();

                // Test list.
                List<Test> tests = testBLO.ToList(ref noList, page, keyWord, createdBy, actualUser, subjectId, column, sort);

                // States.
                ViewBag.Msg = TempData["Msg"] as string;
                ViewBag.Page = page;
                ViewBag.KeyWord = keyWord;
                ViewBag.SubjectId = subjectId;
                ViewBag.Column = column;
                ViewBag.Sort = sort;
                ViewBag.CreatedBy = createdBy;
                ViewBag.ActualUser = actualUser;
                ViewBag.Subject = subjectBLO.Find(subjectId);
                var createdBys = new List<CreatedByModel>() { 
                    new CreatedByModel() { Value = "mine", Text = "Mine" },
                    new CreatedByModel() { Value = "admin", Text = "Admin" },
                    new CreatedByModel() { Value = "teachers", Text = "Teachers" },
                    //new CreatedByModel() { Value = "students", Text = "Students" },
                    new CreatedByModel() { Value = "actualUser", Text = "Actual People" }                
                };
                ViewBag.CreatedByList = new SelectList(createdBys, "Value", "Text");
                var ActualUserList = userBLO.ToList().OrderBy(u => u.FullName).Select(u => new { Value = u.UserId, Text = u.FullName + " - " + u.Username });
                ViewBag.ActualUserList = new SelectList(ActualUserList, "Value", "Text");
                ViewBag.NoList = noList;

                // Return.
                var pageNumber = page ?? 1;
                var onePageOfTests = tests.ToPagedList(pageNumber, 10);
                ViewBag.onePageOfTests = onePageOfTests;
                return Request.IsAjaxRequest()
                    ? (ActionResult)PartialView("_List")
                    : View();
            }
            catch (Exception)
            {
                // Wrtite to log file.
                return RedirectToAction("Index", "Error");
            }
        }

        public ActionResult Details(int id)
        {
            var test = testBLO.Find(id);

            // Authorize.
            if (test == null)
            {
                return HttpNotFound();
            }
            if (!HttpContext.User.IsInRole("1"))
            {
                if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), test.SubjectId))
                {
                    var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                    if (user == null)
                    {
                        return RedirectToAction("Error", "Account");
                    }
                    if (!user.IsActivated)
                    {
                        return RedirectToAction("Error", "Account");
                    }

                    TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                    return RedirectToAction("Index", "Subject");
                }
                if (!test.IsActivated)
                {
                    TempData["Msg"] = "You can not access this test. Please contact Admin to more details.";
                    return RedirectToAction("Index", new { subjectId = test.SubjectId });
                }
            }

            ViewBag.Msg = TempData["Msg"] as string;
            return View(test);
        }

        public ActionResult TestQuestions(int id = 0)
        {
            var test = testBLO.Find(id);

            // Authorize.
            if (test == null)
            {
                return HttpNotFound();
            }
            if (!HttpContext.User.IsInRole("1"))
            {
                if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), test.SubjectId))
                {
                    var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                    if (user == null)
                    {
                        return RedirectToAction("Error", "Account");
                    }
                    if (!user.IsActivated)
                    {
                        return RedirectToAction("Error", "Account");
                    }

                    TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                    return RedirectToAction("Index", "Subject");
                }

                if (!test.IsActivated)
                {
                    TempData["Msg"] = "You can not access this test. Please contact Admin to more details.";
                    return RedirectToAction("Index", new { subjectId = test.SubjectId });
                }
            }

            // Test Question Total page.
            ViewBag.totalPage = test.TestQuestions.Count % 10 == 0 ? test.TestQuestions.Count / 10 : ((test.TestQuestions.Count - (test.TestQuestions.Count % 10))) / 10 + 1;
            return View(test);
        }

        public ActionResult TestResults(int id = 0)
        {
            var test = testBLO.Find(id);

            // Authorize.
            if (test == null)
            {
                return HttpNotFound();
            }
            if (!HttpContext.User.IsInRole("1"))
            {
                if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), test.SubjectId))
                {
                    var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                    if (user == null)
                    {
                        return RedirectToAction("Error", "Account");
                    }
                    if (!user.IsActivated)
                    {
                        return RedirectToAction("Error", "Account");
                    }

                    TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                    return RedirectToAction("Index", "Subject");
                }

                if (!test.IsActivated)
                {
                    TempData["Msg"] = "You can not access this test. Please contact Admin to more details.";
                    return RedirectToAction("Index", new { subjectId = test.SubjectId });
                }
            }

            var userTests = userTestBLO.ToList(id).Where(u => u.UserId == int.Parse(HttpContext.User.Identity.Name)).ToList();
            ViewBag.totalPageResult = userTests.Count % 10 == 0 ? userTests.Count / 10 : ((userTests.Count - (userTests.Count % 10))) / 10 + 1;

            return View(test);
        }

        public ActionResult Create(int subjectId = 0, int testTypeId = 0)
        {
            try
            {
                var subject = subjectBLO.Find(subjectId);

                // Authorize.
                if (subject == null)
                {
                    return HttpNotFound();
                }
                if (!HttpContext.User.IsInRole("1"))
                {
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), subjectId))
                    {
                        //var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                        //if (user == null)
                        //{
                        //    return RedirectToAction("Error", "Account");
                        //}
                        //if (!user.IsActivated)
                        //{
                        //    return RedirectToAction("Error", "Account");
                        //}

                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Subject");
                    }
                }

                // Save states.
                ViewBag.SubjectId = subjectId;
                ViewBag.Subject = subject;

                // Get TestType
                List<TestType> testTypes;
                var userRoleId = userBLO.Find(int.Parse(HttpContext.User.Identity.Name)).RoleId;
                testTypes = testTypeBLO.ToList();
                ViewBag.TestTypeList = new SelectList(testTypes, "TestTypeId", "Name");

                // Get Section of User
                var sections = sectionBLO.ToList(subjectId, int.Parse(HttpContext.User.Identity.Name));
                ViewBag.SectionList = new SelectList(sections, "SectionId", "Name");

                // Generate CustomTestModel
                var customTestModel = customTestBLO.GenerateCustomTestModel(subjectId, 0);
                customTestModel.TestTypeId = testTypeId;
                return View(customTestModel);
            }
            catch (Exception)
            {
                // Wrtite to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        [HttpPost]
        public ActionResult Create(CustomTestModel customTestModel)
        {
            try
            {
                var subject = subjectBLO.Find(customTestModel.SubjectId);

                // Save states.
                ViewBag.Subject = subject;
                ViewBag.SubjectId = customTestModel.SubjectId;
                if (customTestModel.SectionId > 0)
                {
                    var section = sectionBLO.Find(customTestModel.SectionId);
                    ViewBag.Section = section;
                }

                var testTypes = testTypeBLO.ToList();
                ViewBag.TestTypeList = new SelectList(testTypes, "TestTypeId", "Name", customTestModel.TestTypeId);

                if (ModelState.IsValid)
                {
                    // Validate use checking.
                    var validationResult = testBLO.ValidateCustomTest(customTestModel);
                    // Invalid.
                    if (!validationResult.Equals("valid"))
                    {
                        // Set error message.
                        ModelState.AddModelError("", validationResult);
                        return View(customTestModel);
                    }

                    // Classic test or game test.
                    if (customTestModel.TestTypeId == 1)
                    {
                        // Add new Test.
                        var test = testBLO.AddTest(customTestModel);

                        if (test != null)
                        {
                            TempData["Msg"] = "New test has been created.";
                            return RedirectToAction("Details", "Test", new { id = test.TestId });
                        }
                        ModelState.AddModelError("", "An error occurred.");
                    }
                    // Quick Test
                    if (customTestModel.TestTypeId == 2)
                    {
                        // Checking Selected Section
                        if (customTestModel.SectionId == 0)
                        {
                            ViewBag.Error = "Please select Section.";
                            return View(customTestModel);
                        }

                        // Checking Questions in Section
                        var sectionQuestions = sectionQuestionBLO.Find(customTestModel.SectionId);
                        if (sectionQuestions.Count <= 0)
                        {
                            ViewBag.Error = "No question in this Section.";
                            return View(customTestModel);
                        }

                        Session["Custome"] = customTestModel;
                        ViewBag.Number = customTestModel.SectionId;

                        return RedirectToAction("Introduction", new { sectionId = customTestModel.SectionId, subjectId = customTestModel.SubjectId });
                    }
                }

                return View(customTestModel);
            }
            catch (Exception)
            {
                //Wrtite to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        public JsonResult AutocompleteSection(string term, int subjectId = 0)
        {
            var result = sectionBLO.ToList(term, subjectId).Select(u => new { id = u.SectionId, value = "(" + u.SectionQuestions.Count(sq => sq.Question.IsActivated) + ") " + u.Name + " @ " + u.User.FullName + " - " + u.User.Username + "" }).ToList();
            return Json(result, JsonRequestBehavior.AllowGet);
        }

        public JsonResult AutocompleteUser(string term)
        {
            try
            {
                var users = userBLO.ToList();
                var result = users.Where(u => (u.FullName.ToLower().Contains(term.ToLower()))
                    || (u.Username.ToLower().Contains(term.ToLower()))).Select(u => new { id = u.UserId, value = u.FullName + " - " + u.Username });
                return Json(result, JsonRequestBehavior.AllowGet);
            }
            catch (Exception)
            {
                // Write to log file.
                return null;
            }
        }

        public ActionResult Edit(int id)
        {
            try
            {
                var test = testBLO.Find(id);

                // Authorize.
                if (test == null)
                {
                    return HttpNotFound();
                }
                if (!HttpContext.User.IsInRole("1"))
                {
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), test.SubjectId))
                    {
                        var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                        if (user == null)
                        {
                            return RedirectToAction("Error", "Account");
                        }
                        if (!user.IsActivated)
                        {
                            return RedirectToAction("Error", "Account");
                        }

                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Subject");
                    }

                    if (!test.IsActivated)
                    {
                        TempData["Msg"] = "You can not access this test. Please contact Admin to more details.";
                        return RedirectToAction("Index", new { subjectId = test.SubjectId });
                    }
                }

                // Check is using test.
                if (testBLO.CheckIsUsingTest(id))
                {
                    TempData["Msg"] = "The test is using.";
                    return RedirectToAction("Details", new { id = id });
                }

                var customTestModel = customTestBLO.GenerateCustomTestModel(0, id);
                ViewBag.Subject = subjectBLO.Find(test.SubjectId);
                return View(customTestModel);
            }
            catch (Exception)
            {
                // Wrtite to log file.
                return RedirectToAction("Index", "Error");
            }
        }

        [HttpPost]
        public ActionResult Edit(CustomTestModel customTestModel)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    int result = testBLO.Modify(customTestModel);
                    if (result > 0)
                    {
                        TempData["Msg"] = "The test has been updated.";
                        return RedirectToAction("Details", new { id = customTestModel.TestId });
                    }
                    else if (result == -1)
                    {
                        TempData["Msg"] = "The data is out of date. Update unsuccessful";
                        return RedirectToAction("Details", "Test", new { id = customTestModel.TestId });
                    }
                    else if (result == -2)
                    {
                        ModelState.AddModelError("", "The test is using.");
                    }
                    else
                    {
                        ModelState.AddModelError("", "An error occurred.");
                    }
                }
                ViewBag.Subject = subjectBLO.Find(customTestModel.SubjectId);
                return View(customTestModel);
            }
            catch (Exception)
            {
                // Write to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        public string Deactivate(string ids = "")
        {
            try
            {
                int result = testBLO.Deactivate(ids);
                if (result > 0)
                {
                    if (result == 1)
                    {
                        return "The test has been deactivated.";
                    }
                    else
                    {
                        return result + " tests has been deactivated.";
                    }
                }
                else
                {
                    return "An error occurred.";
                }
            }
            catch (Exception)
            {
                // Write to log file.
                return "An error occurred.";
            }
        }

        public string Activate(string ids = "")
        {
            try
            {
                int result = testBLO.Activate(ids);
                if (result > 0)
                {
                    if (result == 1)
                    {
                        return "The test has been activated.";
                    }
                    else
                    {
                        return result + " tests has been activated.";
                    }
                }
                else
                {
                    return "An error occurred.";
                }
            }
            catch (Exception)
            {
                // Write to log file.
                return "An error occurred.";
            }
        }

        public string Delete(string ids = "")
        {
            try
            {
                int result = testBLO.Remove(ids);
                if (result > 0)
                {
                    if (result == 1)
                    {
                        return "The test has been deleted.";
                    }
                    else
                    {
                        return result + " tests has been deleted.";
                    }
                }
                else if (result == -1)
                {
                    return "The test is using.";
                }
                else
                {
                    return "You can not delete this test.";
                }
            }
            catch (Exception)
            {
                // Write to log file.
                return "An error occurred.";
            }
        }

        public int CheckUnfinishedTest()
        {
            try
            {
                var result = userTestBLO.CheckIsUnfinishedTest(int.Parse(HttpContext.User.Identity.Name));
                if (result > 0)
                {
                    return result;
                }
                return 0;
            }
            catch (Exception)
            {
                // Wrtite to log file.
                return 0;
            }
        }

        public ActionResult TakeTheTest(int testId = 0)
        {
            try
            {
                // Close all existent usertest.
                userTestBLO.Close(int.Parse(HttpContext.User.Identity.Name));

                var test = testBLO.Find(testId);

                // Authorize.
                if (test == null)
                {
                    return HttpNotFound();
                }
                if (!HttpContext.User.IsInRole("1"))
                {
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), test.SubjectId))
                    {
                        var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                        if (user == null)
                        {
                            return RedirectToAction("Error", "Account");
                        }
                        if (!user.IsActivated)
                        {
                            return RedirectToAction("Error", "Account");
                        }

                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Subject");
                    }

                    if (!test.IsActivated)
                    {
                        TempData["Msg"] = "You can not access this test. Please contact Admin to more details.";
                        return RedirectToAction("Index", new { subjectId = test.SubjectId });
                    }

                    if (test.Expires < DateTime.Now)
                    {
                        TempData["Msg"] = "This test is no longer available.";
                        return RedirectToAction("Details", new { id = test.TestId });
                    }
                }

                if (test.Expires < DateTime.Now)
                {
                    TempData["Msg"] = "This test is no longer available.";
                    return RedirectToAction("Details", new { id = test.TestId });
                }

                // Add new usertest.
                var userTestId = testBLO.AddUserTest(int.Parse(HttpContext.User.Identity.Name), test.TestId);

                return RedirectToAction("Test", new { userTestId = userTestId });
            }
            catch (Exception)
            {
                // Write to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        public ActionResult Test(int userTestId = 0)
        {
            try
            {
                var userTest = userTestBLO.Find(userTestId);

                // Authorize.
                if (userTest == null)
                {
                    return HttpNotFound();
                }
                if (!HttpContext.User.IsInRole("1"))
                {
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), userTest.Test.SubjectId))
                    {
                        var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                        if (user == null)
                        {
                            return RedirectToAction("Error", "Account");
                        }
                        if (!user.IsActivated)
                        {
                            return RedirectToAction("Error", "Account");
                        }

                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Subject");
                    }

                    if (!userTest.Test.IsActivated)
                    {
                        TempData["Msg"] = "You can not access this test. Please contact Admin to more details.";
                        return RedirectToAction("Index", new { subjectId = userTest.Test.SubjectId });
                    }

                    if (userTest.Test.Expires < DateTime.Now)
                    {
                        TempData["Msg"] = "This test is no longer available.";
                        return RedirectToAction("Details", new { id = userTest.Test.TestId });
                    }
                }

                if (userTest.Test.Expires < DateTime.Now)
                {
                    TempData["Msg"] = "This test is no longer available.";
                    return RedirectToAction("Details", new { id = userTest.Test.TestId });
                }

                // Check the user test is finish or not.
                if (userTest.FinishTime != null)
                {
                    return HttpNotFound();
                }

                var subject = subjectBLO.Find(userTest.Test.SubjectId);
                var test = testBLO.Find(userTest.TestId.Value);

                // Generate TestModel by test id and user id.
                var testModel = testBLO.GenerateTestModel(test.TestId, userTestId);

                // For Matching Question only (column B).
                foreach (var t in testModel.Questions)
                {
                    if (t.QuestionTypeId == 3)
                    {
                        foreach (var a in t.Answers)
                        {
                            string name = t.QuestionId.ToString() + "-" + a.AnswerId.ToString();
                            ViewData[name] = new SelectList(t.Matchs, "MatchId", "Content", a.MatchId);
                        }
                    }
                }

                // States.
                ViewBag.SubjectName = subject.Name;
                ViewBag.Time = userTest.StartTime.AddMinutes(test.Duration).Subtract(DateTime.Now).TotalSeconds;
                ViewBag.CurrentPage = 1;
                ViewBag.totalPage = testModel.Questions.Count % 10 == 0 ? testModel.Questions.Count / 10 : ((testModel.Questions.Count - (testModel.Questions.Count % 10))) / 10 + 1;

                return View(testModel);
            }
            catch (Exception)
            {
                // Write to log file.
                return RedirectToAction("Index", "Error");
            }
        }

        [HttpPost]
        public ActionResult Test(int? currentPage, TestModel testModel, string submit = "")
        {
            try
            {
                var addResult = 0;
                var userTest = userTestBLO.Find(testModel.userTestId);
                var subject = subjectBLO.Find(userTest.Test.SubjectId);

                switch (submit)
                {
                    case "Submit And Finish":
                        addResult = testBLO.AddUserAnswers(testModel);
                        if (addResult > 0)
                        {
                            // Calculate grade.
                            testBLO.CalculateGrade(testModel);

                            // Send result.
                            ViewBag.SubjectName = subject.Name;
                            Session["TestModel"] = testModel;
                            return RedirectToAction("TestResult");
                        }
                        else
                        {
                            return RedirectToAction("Index", "Error");
                        }

                    case "Save Without Submit":

                        addResult = testBLO.AddUserAnswers(testModel);

                        if (addResult > 0)
                        {
                            // For Matching Question only (column B).
                            foreach (var t in testModel.Questions)
                            {
                                if (t.QuestionTypeId == 3)
                                {
                                    foreach (var a in t.Answers)
                                    {
                                        string name = t.QuestionId.ToString() + "-" + a.AnswerId.ToString();
                                        ViewData[name] = new SelectList(t.Matchs, "MatchId", "Content", a.MatchId);
                                    }
                                }
                            }

                            // States.
                            ViewBag.CurrentPage = currentPage;
                            ViewBag.totalPage = testModel.Questions.Count % 10 == 0 ? testModel.Questions.Count / 10 : ((testModel.Questions.Count - (testModel.Questions.Count % 10))) / 10 + 1;
                            ViewBag.SubjectName = subject.Name;
                            var test = testBLO.Find(userTest.TestId.Value);
                            ViewBag.Time = userTest.StartTime.AddMinutes(test.Duration).Subtract(DateTime.Now).TotalSeconds;

                            return View(testModel);
                        }
                        else
                        {
                            return RedirectToAction("Index", "Error");
                        }

                    case "Quit Test":

                        break;

                    default: break;
                }

                return RedirectToAction("Index", "Error");
            }
            catch (Exception)
            {
                // Write to log file.
                return RedirectToAction("Index", "Error");
            }
        }

        public ActionResult TestResult(int id = 0)
        {
            try
            {
                var testModel = new TestModel();
                ViewBag.QuestionList = questionBLO.ToList();
                // View test result
                if(id >0)
                {
                    var userTest = userTestBLO.Find(id);
                    if(userTest.UserId!=int.Parse(HttpContext.User.Identity.Name))
                    {
                        return HttpNotFound();
                    }
                    if (userTest.TestId != null)
                    {
                        var test = testBLO.Find((int) userTest.TestId);

                        // questions info
                        var questions = new List<QuestionModel>();
                        foreach (var item in userAnswerBLO.GetQuestions(userTest.UserTestId))
                        {
                            // answers info
                            var answers = userAnswerBLO.GetAnswers(userTest.UserTestId, item.QuestionId);

                            var question = questionBLO.Find(item.QuestionId);
                            var questionModel = new QuestionModel();
                            questionModel.Content = question.Content;
                            questionModel.Explanation = question.Explanation;
                            questionModel.QuestionId = question.QuestionId;
                            questionModel.QuestionTypeId = question.QuestionTypeId;
                            questionModel.Title = question.Title;
                            questionModel.Answers = answers;
                            questions.Add(questionModel);
                        }
                        // add test info into testmodel
                        testModel.Duration = test.Duration;
                        if (userTest.FinishTime != null) testModel.FinishTime = (DateTime) userTest.FinishTime;
                        if (userTest.Mark != null) testModel.Mark = (double) userTest.Mark;
                        testModel.NumberOfQuestions = test.TestQuestions.Count();
                        testModel.StartTime = userTest.StartTime;
                        testModel.Subject = test.Subject.Name;
                        testModel.Title = test.Title;
                        testModel.userTestId = id;
                        testModel.Questions = questions;
                        // calculator grade
                        testBLO.CalculateGrade(testModel);
                    }
                } else // Test result after take the test
                {
                    testModel = Session["TestModel"] as TestModel;

                    if (testModel == null)
                    {
                        return HttpNotFound();
                    }
                }
                ViewBag.totalPage = testModel.Questions.Count % 10 == 0 ? testModel.Questions.Count / 10 : ((testModel.Questions.Count - (testModel.Questions.Count % 10))) / 10 + 1;
                return View(testModel);
            }
            catch (Exception)
            {
                // Write to log file.
                return RedirectToAction("Index", "Error");
            }
        }

        public ActionResult Introduction(int sectionId, int subjectId)
        {
            var section = sectionBLO.Find(sectionId);
            if (section == null)
            {
                TempData["Msg"] = "This section has been deleted by Owner. Please select other!";
                return RedirectToAction("Index", "Test", new { subjectId = subjectId });
            }
            if (!section.IsActivated)
            {
                TempData["Msg"] = "This section has been deactivate by Admin. Please select other!";
                return RedirectToAction("Index", "Test", new { subjectId = section.SubjectId });
            }

            if (!HttpContext.User.IsInRole("1"))
            {
                if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), section.SubjectId))
                {
                    var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                    if (user == null)
                    {
                        return RedirectToAction("Error", "Account");
                    }
                    if (!user.IsActivated)
                    {
                        return RedirectToAction("Error", "Account");
                    }

                    TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                    return RedirectToAction("Index", "Subject");
                }
            }

            var subject = subjectBLO.Find(section.SubjectId);

            ViewBag.Section = sectionId;
            ViewBag.Subject = subject;

            return View();
        }

        public ActionResult QuickTest(int sectionId)
        {
            try
            {
                // Get section and subject
                var section = sectionBLO.Find(sectionId);

                if (section == null)
                {
                    TempData["Msg"] = "This section has been deleted by Owner. Please select other!";
                    return RedirectToAction("Index", "Test", new { subjectId = section.SubjectId });
                }
                if (!section.IsActivated)
                {
                    TempData["Msg"] = "This section has been deactivate by Admin. Please select other!";
                    return RedirectToAction("Index", "Test", new { subjectId = section.SubjectId });
                }

                var subject = subjectBLO.Find(section.SubjectId);
                if (!HttpContext.User.IsInRole("1"))
                {
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), subject.SubjectId))
                    {
                        var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                        if (user == null)
                        {
                            return RedirectToAction("Error", "Account");
                        }
                        if (!user.IsActivated)
                        {
                            return RedirectToAction("Error", "Account");
                        }

                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Subject");
                    }
                }

                // Get Id of User
                var userId = int.Parse(HttpContext.User.Identity.Name);

                // Add new UserTest
                var userTest = userTestBLO.AddQuickTest(userId);

                // Generate TestModel
                var testModel = testBLO.GenerateTestModel(userTest.UserTestId);
                testModel.NumberOfQuestions = section.SectionQuestions.Count;
                testModel.Subject = subject.Name;

                // Select one Question
                var questionId = testBLO.SelectOneQuestion(testModel, sectionId);

                // Add Question to TestModel
                testModel = testBLO.AddQuestionModel(testModel, questionId);

                // Get list Matches if Question type is Matching
                const int currentQuestion = 0;
                if (testModel.Questions[currentQuestion].QuestionTypeId == 3)
                {
                    var name = testModel.Questions[currentQuestion].QuestionId.ToString();
                    ViewData[name] = new SelectList(testModel.Questions[currentQuestion].Matchs, "MatchId", "Content");
                }

                ViewBag.User = userBLO.Find(userId);
                ViewBag.Grade = 0;
                ViewBag.Subject = subject;
                ViewBag.Time = 0;
                ViewBag.CurrentQuestion = currentQuestion;
                ViewBag.FirstTime = "True";
                ViewBag.Section = section;

                if (currentQuestion == (section.SectionQuestions.Count - 1))
                {
                    ViewBag.FinishQuestion = "True";
                }

                return View(testModel);
            }
            catch (Exception)
            {
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        [HttpPost]
        public ActionResult QuickTest(int currentQuestion, TestModel testModel, string submit = "")
        {
            try
            {
                var userTest = userTestBLO.Find(testModel.userTestId);
                var sectionId = int.Parse(Request.Form["SectionId"]);
                Subject subject;

                switch (submit)
                {
                    case "Next":
                        currentQuestion += 1;

                        // Select Question
                        var questionId = testBLO.SelectOneQuestion(testModel, sectionId);

                        // Generate TestModel
                        testModel = testBLO.AddQuestionModel(testModel, questionId);
                        testModel.Mark = userTest.Mark.Value;
                        ModelState.Clear();

                        // For Matching Question only (column B).
                        if (testModel.Questions[currentQuestion].QuestionTypeId == 3)
                        {
                            var name = testModel.Questions[currentQuestion].QuestionId.ToString();
                            ViewData[name] = new SelectList(testModel.Questions[currentQuestion].Matchs, "MatchId",
                                                            "Content");
                        }

                        ViewBag.CurrentQuestion = currentQuestion;
                        ViewBag.Time = DateTime.Now.Subtract(userTest.StartTime).TotalSeconds;

                        subject = subjectBLO.Find(testModel.Questions[currentQuestion].SubjectId);
                        ViewBag.Subject = subject;

                        var userId = int.Parse(HttpContext.User.Identity.Name);
                        ViewBag.User = userBLO.Find(userId);

                        ViewBag.Section = sectionBLO.Find(sectionId);

                        return View(testModel);

                    case "Result":
                        //if (userTest.FinishTime != null)
                        //{
                        //    ViewBag.Error = "This Quick Test has been finished!";
                        //    subject = subjectBLO.Find(testModel.Questions[currentQuestion].SubjectId);
                        //    ViewBag.Subject = subject;
                        //    return View(testModel);
                        //}

                        //testModel = testBLO.FinishQuickTest(testModel);
                        //if (testModel == null)
                        //{
                        //    return RedirectToAction("Index", "Error", new { Area = "" });
                        //}

                        //TempData["QuickTestResult"] = testModel;
                        //sectionId = int.Parse(Request.Form["SectionId"]);
                        //TempData["Section"] = sectionBLO.Find(sectionId);

                        //ModelState.Clear();
                        //return RedirectToAction("QuickTestResult");

                        if (userTest.FinishTime == null)
                        {
                            testBLO.FinishQuickTest(testModel.userTestId);
                        }
                        testModel = testBLO.FinishQuickTest(testModel);
                        TempData["QuickTestResult"] = testModel;
                        sectionId = int.Parse(Request.Form["SectionId"]);
                        TempData["Section"] = sectionBLO.Find(sectionId);

                        ModelState.Clear();
                        return RedirectToAction("QuickTestResult");
                }
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
            catch (Exception)
            {
                // Write to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        public ActionResult QuickTestResult()
        {
            var testModel = TempData["QuickTestResult"] as TestModel;

            var userTest = userTestBLO.Find(testModel.userTestId);
            var question = questionBLO.Find(testModel.Questions.LastOrDefault().QuestionId);

            var subject = subjectBLO.Find(question.SubjectId);
            ViewBag.Subject = subject;

            var section = TempData["Section"] as Section;
            ViewBag.Section = section;

            // Get Time
            if (userTest.FinishTime != null)
            {
                ViewBag.Minutes = userTest.FinishTime.Value.Subtract(userTest.StartTime).Minutes;
                ViewBag.Seconds = userTest.FinishTime.Value.Subtract(userTest.StartTime).Seconds;
            }
            return View(testModel);
        }

        public double CheckAnswer(string answerId, int userTestId, bool grade, string matchingId, int sectionId)
        {
            double mark = 0;
            if (!grade)
            {
                if (matchingId == null)
                {
                    var spliter = new StringHelper();

                    // Split id string to int array.
                    var idInt = spliter.Split(answerId);
                    foreach (var id in idInt)
                    {
                        var answer = answerBLO.Find(id);
                        userAnswerBLO.Add(userTestId, answer.QuestionId, answer.AnswerId, 0);
                        mark += answer.Grade;
                    }

                    if (mark >= 99)
                    {
                        mark = 100;
                    }

                    userTestBLO.Modify(userTestId, mark);
                }
                else
                {
                    var spliter = new StringHelper();

                    // Split id string to int array.
                    var answerIdInt = spliter.Split(answerId);
                    var matchIdInt = spliter.Split(matchingId);

                    for (var i = 0; i < answerIdInt.Count(); i++)
                    {
                        var answer = answerBLO.Find(answerIdInt[i]);
                        userAnswerBLO.Add(userTestId, answer.QuestionId, answer.AnswerId, matchIdInt[i]);
                        if (answer.MatchId == matchIdInt[i])
                        {
                            mark += answer.Grade;
                        }
                    }

                    if (mark >= 99)
                    {
                        mark = 100;
                    }

                    userTestBLO.Modify(userTestId, mark);
                }
            }

            var userTest = userTestBLO.Find(userTestId);
            var section = sectionBLO.Find(sectionId);
            if (userTest.UserAnswers.Count == section.SectionQuestions.Count)
            {
                testBLO.FinishQuickTest(userTestId);
            }

            return Math.Round(mark, 2);
        }

        public string FindTrueAnswer(int questionId, int userTestId)
        {
            try
            {
                string answerId = "";
                var question = questionBLO.Find(questionId);
                var answers = question.Answers;

                if (question.QuestionTypeId == 1 || question.QuestionTypeId == 4)
                    foreach (var answer in answers)
                    {
                        if (answer.Grade > 0)
                        {
                            return answer.AnswerId.ToString();
                        }
                    }
                if (question.QuestionTypeId == 2)
                {
                    foreach (var answer in answers)
                    {
                        if (answer.Grade > 0)
                        {
                            answerId += answer.AnswerId.ToString() + "-";
                        }
                    }
                    return answerId;
                }
                if (question.QuestionTypeId == 3)
                {
                    foreach (var answer in answers)
                    {
                        answerId += answer.AnswerId.ToString() + "-" + answer.MatchId.ToString() + "E";
                    }
                    return answerId;
                }
                return "";
            }
            catch (Exception)
            {
                return "";
            }
        }

        public ActionResult CreateChart(int testId)
        {
            var helper = new ChartHelper();
            var chart = new Chart();
            var yValue = testBLO.CreateChart(testId);
            if(yValue==null)
            {
                return null;
            }
            chart.Width = 700;
            chart.Height = 300;
            chart.BackColor = Color.FromArgb(211, 223, 240);
            chart.BorderlineDashStyle = ChartDashStyle.Solid;
            chart.BackSecondaryColor = Color.White;
            chart.BackGradientStyle = GradientStyle.TopBottom;
            chart.BorderlineWidth = 1;
            chart.Palette = ChartColorPalette.BrightPastel;
            chart.BorderlineColor = Color.FromArgb(26, 59, 105);
            chart.RenderType = RenderType.BinaryStreaming;
            chart.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
            chart.AntiAliasing = AntiAliasingStyles.All;
            chart.TextAntiAliasingQuality = TextAntiAliasingQuality.Normal;
            chart.Titles.Add(helper.CreateTitle("TestChart"));
            chart.Series.Add(helper.CreateSeries(yValue, "TestChart", null));
            chart.ChartAreas.Add(helper.CreateChartArea("TestChart"));

            var ms = new MemoryStream();
            chart.SaveImage(ms);

            return File(ms.GetBuffer(), @"image/png");
        }
    }
}
